import type { AxiosRequestAdapter } from '@alova/adapter-axios';
import type { Method } from 'alova';
import type { ResponseErrorInterceptHandler } from 'alova/client';
import type { VueHookType } from 'alova/vue';
import type { AxiosError } from 'axios';

import { preferences } from '@vben/preferences';

import { axiosRequestAdapter } from '@alova/adapter-axios';
import { createAlova } from 'alova';
import { createServerTokenAuthentication } from 'alova/client';
import VueHook from 'alova/vue';
import { message } from 'ant-design-vue';

import { formatStatusMessage } from '#/utils/alova/utils';

export interface AlovaConfig {
  baseURL: string;
  timeout?: number;
  beforeRequest?: (method: Method) => void;
  assignToken: (method: Method) => void;
  doReAuthenticate: () => Promise<any>;
  doRefreshToken: () => Promise<any>;
}

export // docs path of alova.js https://alova.js.org/
function createAlovaInstance(alovaConfig: AlovaConfig) {
  const { assignToken, doReAuthenticate, doRefreshToken, ...restConfig } =
    alovaConfig;
  const _alovaConfig = { timeout: 15 * 1000, ...restConfig };

  const handleRefreshToken: ResponseErrorInterceptHandler<
    AxiosRequestAdapter
  > = async (error, method) => {
    if (!preferences.app.enableRefreshToken || method.meta.__isRetryRequest) {
      await doReAuthenticate();
      throw error;
    }
    method.meta.__isRetryRequest = true;

    try {
      await doRefreshToken();
    } catch (refreshError) {
      console.error('Refresh token failed, please login again.');
      await doReAuthenticate();

      throw refreshError;
    } finally {
      method.meta.__isRetryRequest = false;
    }
  };

  const { onAuthRequired, onResponseRefreshToken } =
    createServerTokenAuthentication<VueHookType, AxiosRequestAdapter>({
      // 服务端判定token过期
      refreshTokenOnError: {
        // 当服务端返回401时，表示token过期
        isExpired: async (error) => {
          return error.response.status === 401;
        },

        // 当token过期时触发，在此函数中触发刷新token
        handler: handleRefreshToken,
      },
      // 添加token到请求头
      assignToken,
    });

  return createAlova({
    statesHook: VueHook,
    requestAdapter: axiosRequestAdapter(),
    cacheFor: null,
    baseURL: _alovaConfig.baseURL,
    timeout: _alovaConfig.timeout,

    beforeRequest: onAuthRequired((method) => {
      if (method.meta?.isFormPost) {
        method.config.headers['Content-Type'] =
          'application/x-www-form-urlencoded';
        method.data = new URLSearchParams(
          method.data as URLSearchParams,
        ).toString();
      }
      alovaConfig.beforeRequest?.(method);
    }),
    responded: onResponseRefreshToken({
      // 请求成功的拦截器
      onSuccess: async (response) => {
        return response.data;
      },
      onError: (error: AxiosError<any>) => {
        const status = error.status;
        const responseData = error?.response?.data ?? {};
        const errorMessage = responseData?.error ?? responseData?.message ?? '';
        if (errorMessage) {
          message.error(errorMessage);
        } else {
          message.error(formatStatusMessage(status));
        }
      },

      onComplete: async (_method) => {
        // 处理请求完成逻辑
      },
    }),
  });
}
